import React, { useState, useEffect } from 'react';
import styles from './fabu.module.css';
import { NavBar, Toast, Input, Uploader } from 'react-vant';
import { useNavigate,useSearchParams } from 'react-router-dom';
import SparkMD5 from 'spark-md5';

const DEFAULT_CHUNK_SIZE = 1024 * 1024; // 默认 1MB
const MAX_CONCURRENCY = 6; // 最大并发数
const CONCURRENCY_RECOVERY_INTERVAL = 10000; // 并发数恢复间隔（毫秒），延长恢复时间
const MAX_RETRY_TIME = 60000; // 最大重试时间（毫秒）
const MAX_RETRIES = 3; // 最大重试次数

export default function Fabu() {
    const navigate = useNavigate();
    const [searchParams] = useSearchParams();
    const id= searchParams.get('id');
    const [fileName, setFileName] = useState('');
    const [fileHash, setFileHash] = useState('');
    const [fileUrl, setFileUrl] = useState('');
    const [fileType, setFileType] = useState('');
    const [currentConcurrency, setCurrentConcurrency] = useState(6); // 当前并发数
    const [last429Time, setLast429Time] = useState(0); // 上次遇到429错误的时间
    const [activeRequests, setActiveRequests] = useState(0); // 全局请求计数器
    const [selectedFile, setSelectedFile] = useState(null);
    const [uploadStatus, setUploadStatus] = useState(''); // 上传状态
    const [canUpload, setCanUpload] = useState(false); // 控制是否可以上传
    const [uploadProgress, setUploadProgress] = useState(0); // 上传进度
    const [inputContent, setInputContent] = useState(''); // 输入框的内容

    // 绑定上传事件
    const handleUpload = async (e) => {
        const file = e[0].file;
        console.log(e);

        if (!file) return;

        setSelectedFile(file);
        setFileName(file.name);
        console.log(`文件名: ${file.name}`);
        console.log(`文件大小: ${file.size} bytes`);

        // 计算文件内容 hash 值
        const hash = await calculateHash(file);
        setFileHash(hash);
        setCanUpload(true); // 文件选择完成后，允许上传
    };

    // 获取网络信息并动态调整并发数和切片大小
    const getNetworkInfo = () => {
        const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
        let maxConcurrency = 6;
        let chunkSize = DEFAULT_CHUNK_SIZE;
        if (connection) {
            if (connection.effectiveType.includes('2g')) {
                maxConcurrency = 2;
                chunkSize = 256 * 1024; // 256KB
            } else if (connection.effectiveType.includes('3g')) {
                maxConcurrency = 4;
                chunkSize = 512 * 1024; // 512KB
            }
        }
        return { maxConcurrency, chunkSize };
    };

    // 创建文件分片
    const createChunks = (file, chunkSize) => {
        let start = 0;
        const chunks = [];
        while (start < file.size) {
            chunks.push(file.slice(start, start + chunkSize));
            start += chunkSize;
        }
        return chunks;
    };

    // 计算文件内容 hash 值
    const calculateHash = (file) => {
        return new Promise((resolve) => {
            const fileReader = new FileReader();
            fileReader.readAsArrayBuffer(file);
            fileReader.onload = function (e) {
                const spark = new SparkMD5.ArrayBuffer();
                spark.append(e.target.result);
                resolve(spark.end());
            };
        });
    };

    // 控制请求并发
    // 并发请求函数
    const concurRequest = async (taskPool, max) => {
        // 如果任务池为空，则返回空数组
        if (taskPool.length === 0) {
            return [];
        }

        // 存储请求结果的数组
        const results = [];
        // 当前任务索引
        let index = 0;
        // 当前完成的任务数
        let count = 0;

        // 请求函数
        const request = async () => {
            // 如果任务索引等于任务池长度，则返回
            if (index === taskPool.length) return;
            // 如果当前活跃请求数大于等于最大并发数，则等待一段时间再尝试
            if (activeRequests >= max) {
                await new Promise(resolve => setTimeout(resolve, 100)); // 等待一段时间再尝试
                request();
                return;
            }
            // 增加当前活跃请求数
            setActiveRequests(prev => prev + 1);
            // 获取当前任务
            const i = index;
            const task = taskPool[index];
            // 增加任务索引
            index++;
            try {
                // 执行任务，并将结果存储到结果数组中
                results[i] = await task();
                // 更新上传进度
                setUploadProgress((index / taskPool.length) * 100);
            } catch (err) {
                // 如果任务执行出错，则将错误存储到结果数组中
                results[i] = err;
            } finally {
                // 减少当前活跃请求数
                setActiveRequests(prev => prev - 1);_
                // 增加已完成的任务数
                count++;
                // 如果已完成的任务数等于任务池长度，则返回结果数组
                if (count === taskPool.length) {
                    return results;
                }
                // 继续执行下一个任务
                request();
            }
        };

        // 计算最大并发数和任务池长度的最小值
        const times = Math.min(max, taskPool.length);
        // 并发执行任务
        for (let i = 0; i < times; i++) {
            request();
        }
    };

    // 合并分片请求
    const mergeRequest = async () => {
        // 检查参数是否有效
        if (!fileHash || typeof fileHash!== 'string' ||!fileName || typeof fileName!== 'string') {
            console.error('合并请求缺少必要参数或参数类型错误');
            console.log(`fileHash: ${fileHash}, fileName: ${fileName}`);
            return;
        }
        try {
            console.log('Sending merge request with fileHash:', fileHash, 'and fileName:', fileName);
            const response = await fetch("http://localhost:3000/server/merge", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    fileHash,
                    fileName,
                    inputContent // 添加输入框内容
                }),
            });

            if (!response.ok) {
                const errorData = await response.json().catch(() => ({ msg: '未知错误' }));
                console.error('合并请求出错:', errorData);
                throw new Error(`HTTP error! status: ${response.status}, message: ${errorData.msg}`);
            }
            const data = await response.json();
            console.log('Merge request response:', data);
            return data;
        } catch (error) {
            console.error('合并请求出错:', error);
            throw error;
        }
    };

    // 切片重试机制，引入指数退避算法
    const uploadWithRetry = async (formData, startTime) => {
        let attempt = 0;
        while (attempt < MAX_RETRIES) {
            if (Date.now() - startTime > MAX_RETRY_TIME) {
                console.error(`切片 ${formData.get('chunkHash')} 上传超时，停止重试`);
                throw new Error('上传超时');
            }
            try {
                const response = await fetch("http://localhost:3000/server/upload", {
                    method: "POST",
                    body: formData,
                });
                if (response.status === 429) {
                    // 遇到 429 错误，记录时间并更激进地降低并发数
                    setLast429Time(Date.now());
                    setCurrentConcurrency(prev => Math.max(1, Math.floor(prev * 0.5))); // 降低到当前并发数的一半
                    const retryAfter = parseInt(response.headers.get('Retry-After') || '0', 10);
                    const retryDelay = retryAfter > 0 ? retryAfter * 1000 : Math.pow(2, attempt) * 1000;
                    console.log(`切片 ${formData.get('chunkHash')} 因 429 错误，等待 ${retryDelay}ms 后重试，当前并发数: ${currentConcurrency}`);
                    await new Promise(resolve => setTimeout(resolve, retryDelay));
                } else if (!response.ok) {
                    throw new Error(`请求失败，状态码: ${response.status}`);
                } else {
                    return response;
                }
            } catch (error) {
                attempt++;
                if (attempt === MAX_RETRIES) {
                    console.error(`切片 ${formData.get('chunkHash')} 上传失败，达到最大重试次数`);
                    throw error;
                }
                const retryDelay = Math.pow(2, attempt) * 1000;
                console.log(`切片 ${formData.get('chunkHash')} 上传失败，正在进行第 ${attempt + 1} 次重试，等待 ${retryDelay}ms`);
                await new Promise(resolve => setTimeout(resolve, retryDelay));
            }
        }
    };

    // 上传文件分片
    // 上传分片
    const uploadChunks = async (chunks, existChunks) => {
        // 将分片信息转换为FormData格式
        const formDatas = chunks
           .map((chunk, index) => ({
                fileHash,
                chunkHash: fileHash + "-" + index,
                chunk
            }))
           // 过滤掉已经存在的分片
           .filter((item) => !existChunks.includes(item.chunkHash))
           // 将分片信息转换为FormData格式
           .map((item) => {
                const formData = new FormData();
                formData.append('fileHash', item.fileHash);
                formData.append('chunkHash', item.chunkHash);
                formData.append('chunk', item.chunk);
                return formData;
            });

        // 将分片信息转换为请求任务
        const taskPool = formDatas.map((formData) => () => uploadWithRetry(formData, Date.now()));

        // 控制请求并发
        const { maxConcurrency } = getNetworkInfo();
        setCurrentConcurrency(maxConcurrency);

        // 并发数恢复机制
        const recoveryInterval = setInterval(() => {
            // 如果距离上次429错误超过恢复间隔，并且当前并发数小于最大并发数，则恢复并发数
            if (Date.now() - last429Time > CONCURRENCY_RECOVERY_INTERVAL && currentConcurrency < MAX_CONCURRENCY) {
                setCurrentConcurrency(prev => Math.min(MAX_CONCURRENCY, prev + 1));
                console.log(`并发数恢复到 ${currentConcurrency}`);
            }
        }, CONCURRENCY_RECOVERY_INTERVAL);

        // 并发请求
        await concurRequest(taskPool, currentConcurrency);
        clearInterval(recoveryInterval);

        // 合并分片请求
        const mergeRes = await mergeRequest();
        if (mergeRes && mergeRes.success) {
            // 设置文件URL
            setFileUrl(mergeRes.data.fileUrl);
            // 根据文件扩展名设置文件类型
            setFileTypeBasedOnExtension();
            // 设置上传状态为上传完成
            setUploadStatus('上传完成');
        } else {
            // 设置上传状态为上传失败
            setUploadStatus('上传失败');
        }
    };

    // 设置文件类型
    const setFileTypeBasedOnExtension = () => {
        const fileExtension = fileName.split('.').pop()?.toLowerCase();
        if (['jpg', 'jpeg', 'png', 'gif'].includes(fileExtension || '')) {
            setFileType('image');
        } else if (['mp4', 'webm', 'ogg'].includes(fileExtension || '')) {
            setFileType('video');
        } else {
            setFileType('other');
        }
    };

    // 校验文件、文件分片是否存在
    const verify = async (fileHash, fileName) => {
        try {
            const response = await fetch("http://localhost:3000/server/verify", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({
                    fileHash,
                    fileName,
                    inputContent // 添加输入框内容
                }),
            });
            return response.json();
        } catch (error) {
            console.error('校验请求出错:', error);
            throw error;
        }
    };

    // 直接上传文件
    const directUpload = async (file) => {
        const formData = new FormData();
        formData.append('file', file);
        formData.append('fileName', fileName);
        formData.append('fileHash', fileHash);
        formData.append('inputContent', inputContent); // 添加输入框内容
        formData.append('fileType', fileType); // 添加文件类型
        formData.append('huatiId', id); // 添加帖子ID文件大小

        try {
            const res = await fetch("http://localhost:3000/server/directUpload", {
                method: "POST",
                body: formData,
            });
            const data = await res.json();
            if (data.success) {
                // 提取服务器返回的 fileUrl
                setFileUrl(data.data.fileUrl);
                setFileTypeBasedOnExtension();
                setUploadStatus('上传完成');
                Toast.success('上传成功');
            } else {
                setUploadStatus('上传失败');
            }
        } catch (error) {
            console.error('直接上传出错:', error);
            setUploadStatus('上传失败');
        }
    };

    // 提取上传逻辑到新函数
    const startUpload = async () => {
        if (fileName && fileHash && selectedFile) {
            // 判断文件大小
            const ONE_GB = 500 * 1024 * 1024;
            if (selectedFile.size > ONE_GB) {
                // 获取网络信息
                const { chunkSize } = getNetworkInfo();
                // 创建文件分片
                const chunks = createChunks(selectedFile, chunkSize);

                // 校验文件、文件分片是否存在
                const verifyAndUpload = async () => {
                    const verifyRes = await verify(fileHash, fileName);
                    const { existFile, existChunks } = verifyRes.data;
                    if (existFile) return;

                    // 上传文件分片
                    await uploadChunks(chunks, existChunks);
                };
                verifyAndUpload();
            } else {
                // 直接上传文件
                directUpload(selectedFile);
            }
        }

        // 重置状态
        setFileName('');
        setFileHash('');
        setFileUrl('');
        setFileType('');
        setSelectedFile(null);
        setUploadStatus('');
        setCanUpload(false);
        setUploadProgress(0);
        setInputContent('');
    };

    return (
        <>
            <div className={styles.Big_box}>
                <NavBar
                    title="发动态"
                    leftArrow={false}
                    leftText="取消"
                    rightText="发布"
                    onClickLeft={() => navigate(-1)}
                    onClickRight={() => startUpload()}
                    disabled={!canUpload}
                />

                <div className={styles.box}>
                    <Input.TextArea
                        className={styles.inp}
                        value={inputContent}
                        onChange={(v) => setInputContent(v)}
                        placeholder="自适应高度"
                        autoSize
                    />
                    <Uploader
                        onChange={(v) => handleUpload(v)}
                    />
                    <div>
                        <button className={styles.select_huati} style={{marginRight:'20px'}}>#添加位置</button>
                        <button className={styles.select_huati} onClick={()=>navigate('/selecthuati')}>#话题</button>
                    </div>
                </div>
            </div>
        </>
    );
}